package es

import (
	"context"
	"encoding/json"
	"fmt"
	"gopkg.in/olivere/elastic.v5"
	"log"
	"os"
	"time"
)

type EsService5 struct {
	es5 *elastic.Client
}

// CreateClient 创建一个客户端
func (self *EsService5) CreateClient() {
	// 1.创建客户端
	self.es5, _ = elastic.NewClient(
		elastic.SetURL("http://192.168.0.17:59206"),
		//elastic.SetGzip(true),
		elastic.SetSniff(false), // 将sniff设置为false后，便不会自动转换地址
		elastic.SetHealthcheck(false),
		elastic.SetHealthcheckTimeout(10*time.Second),
		elastic.SetErrorLog(log.New(os.Stderr, "ELASTIC", log.LstdFlags)), // 设置日志输出的名字
		elastic.SetInfoLog(log.New(os.Stdout, "", log.LstdFlags)),         // 输出日志级别
	)
}

func (self *EsService5) AddFields(indexName string, fieldName string, fieldType string) {
	var map1, err = self.es5.GetMapping().Index(indexName).Do(context.Background())
	if err != nil {
		fmt.Println(err)
	}
	mappings := map1[indexName].(map[string]interface{})["mappings"].(map[string]interface{})
	for docType, value := range mappings {
		// 这里可以对key和value进行操作
		properties := value.(map[string]interface{})["properties"].(map[string]interface{})
		_, ok := properties[fieldName]
		if ok {
			// 字段已存在
			panic("字段" + fieldName + "已经存在了!")
		} else {

			newDocType := make(map[string]interface{})
			newDocType["properties"] = self.buildField(fieldName, fieldType)
			// 添加字段
			mapping := make(map[string]interface{})
			mapping[docType] = newDocType
			fmt.Println("字段" + fieldName + "不存在,添加字段")
			_, err := self.es5.PutMapping().Index(indexName).Type(docType).BodyJson(mapping).Do(context.Background())
			if err != nil {
				log.Fatal(err)
			}

		}
	}

}

func (self *EsService5) buildField(fieldName string, fieldType string) map[string]interface{} {
	type_field := make(map[string]interface{})
	new_field := make(map[string]interface{})
	new_field[fieldName] = type_field
	type_field["type"] = fieldType
	if fieldType == "Date" {
		type_field["format"] = "yyyy-MM-dd HH:mm:ss"
	}
	fmt.Println(new_field)
	return new_field
}

func (self *EsService5) Query(boolQuery *elastic.BoolQuery, index string, docType string) int64 {
	var searchResult, err = self.es5.Search(index).Type(docType).Query(boolQuery).Size(1).Do(context.Background())
	fmt.Println(err)
	total := searchResult.Hits.TotalHits
	return total
}

type Result struct {
	Index int
	Data  []map[string]interface{}
	Size  int64
}

func (self *EsService5) Scroll(boolQuery *elastic.BoolQuery, index string, docType string, size int64) *Result {
	ctx := context.Background()
	var result, err = self.es5.Scroll(index).Type(docType).Query(boolQuery).Scroll("5m").FetchSourceContext(elastic.NewFetchSourceContext(true).Include("id", "createTime")).Size(int(size)).Do(ctx)
	fmt.Println(err)

	sid := result.ScrollId
	rs := &Result{Size: result.TotalHits(), Index: 0, Data: make([]map[string]interface{}, result.TotalHits())}
	appendRs(result, rs)
	fmt.Printf("total = %d,len=%d err=%v", result.TotalHits(), len(result.Hits.Hits), err)
	if size < result.TotalHits() {
		for {
			result, err = self.es5.Scroll("5m").ScrollId(sid).Do(ctx) // 每次查询都会使用这个时间续期
			fmt.Printf("total = %d,len=%d, err=%v", result.TotalHits(), len(result.Hits.Hits), err)
			if len(result.Hits.Hits) <= 0 {
				break
			}
			appendRs(result, rs)
			time.Sleep(1 * time.Second)
		}
	}

	// 清除游标
	_, err = self.es5.ClearScroll().ScrollId(result.ScrollId).Do(ctx)
	return rs
}

func appendRs(result *elastic.SearchResult, rs *Result) {
	for _, v := range result.Hits.Hits {
		data, _ := v.Source.MarshalJSON()
		var m map[string]interface{}
		json.Unmarshal(data, &m)
		rs.Data[rs.Index] = m
		//fmt.Println(m)
		rs.Index++
	}
}
